package com.li.commons.util;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.NotFoundException;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

/**
 * 依赖javassit的工具类
 * @author huqilong
 *
 */
public class ClassUtil {
	
	
	/**
	 * 根据类名、方法名，参数类型获取方法名称
	 * @param className
	 * @param methodName
	 * @param method
	 * @param paramTypes
	 * @return
	 */
	public static String[] getMethodParamNames(ClassPool pool,String className,String method, Class<?>... paramTypes) {
		CtClass cc = null;
		CtMethod cm = null;
		try {
			cc = pool.get(className);
			String[] paramTypeNames = new String[paramTypes.length];
			for (int i = 0; i < paramTypes.length; i++){
				paramTypeNames[i] = paramTypes[i].getName();
			}
			cm = cc.getDeclaredMethod(method, pool.get(paramTypeNames));
		} catch (NotFoundException e) {
			e.printStackTrace();
		}finally{
        	if(cc != null) cc.detach();
        }
		return getMethodParamNames(cm);
	}

	/**
	 * 根据类名、方法名，参数类型获取方法名称
	 * @param className
	 * @param methodName
	 * @param method
	 * @param paramTypes
	 * @return
	 */
	public static String[] getMethodParamNames(String className,String method, Class<?>... paramTypes) {
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = null;
		CtMethod cm = null;
		try {
			cc = pool.get(className);
			String[] paramTypeNames = new String[paramTypes.length];
			for (int i = 0; i < paramTypes.length; i++){
				paramTypeNames[i] = paramTypes[i].getName();
			}
			cm = cc.getDeclaredMethod(method, pool.get(paramTypeNames));
		} catch (NotFoundException e) {
			e.printStackTrace();
		}finally{
        	if(cc != null) cc.detach();
        }
		return getMethodParamNames(cm);
	}
	

	/**
	 * 获取方法参数名称，按给定的参数类型匹配方法
	 * 
	 * @param clazz
	 * @param method
	 * @param paramTypes
	 * @return
	 */
	public static String[] getMethodParamNames(Class<?> clazz, String method,Class<?>... paramTypes) {
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = null;
		CtMethod cm = null;
		try {
			cc = pool.get(clazz.getName());
			String[] paramTypeNames = new String[paramTypes.length];
			for (int i = 0; i < paramTypes.length; i++){
				paramTypeNames[i] = paramTypes[i].getName();
			}
			cm = cc.getDeclaredMethod(method, pool.get(paramTypeNames));
		} catch (NotFoundException e) {
			e.printStackTrace();
		}finally{
        	if(cc != null) cc.detach();
        }
		return getMethodParamNames(cm);
	}

	/**
	 * 获取方法参数名称，匹配同名的某一个方法
	 * 
	 * @param clazz
	 * @param method
	 * @return
	 * @throws NotFoundException
	 *             如果类或者方法不存在
	 * @throws MissingLVException
	 *             如果最终编译的class文件不包含局部变量表信息
	 */
	public static String[] getMethodParamNames(Class<?> clazz, String method) {
		ClassPool pool = ClassPool.getDefault();
		CtClass cc=null;
		CtMethod cm = null;
		try {
			cc = pool.get(clazz.getName());
			cm = cc.getDeclaredMethod(method);
		} catch (NotFoundException e) {
			e.printStackTrace();
		}finally{
        	if(cc != null) cc.detach();
        }
		return getMethodParamNames(cm);
	}
	
	/**
	 * 根据方法获取所有参数信息
	 * @param cm
	 * @return
	 */
	protected static String[] getMethodParamNames(CtMethod cm) {
		MethodInfo methodInfo = cm.getMethodInfo();
		CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
		LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute.getAttribute(LocalVariableAttribute.tag);
		if (attr == null) {
			return null;
		}
		String[] paramNames = null;
		try {
			paramNames = new String[cm.getParameterTypes().length];
		} catch (NotFoundException e) {
			e.printStackTrace();
		}
		int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
		for (int i = 0; i < paramNames.length; i++) {
			paramNames[i] = attr.variableName(i + pos);
		}
		return paramNames;
	}
	
	public static void test(String a){
		
	}
	
	public static void main(String args[]){
		String[] parameters = getMethodParamNames("cn.chineseall.utils.ClassUtil","test",String.class);
		for(int i=0;i<parameters.length;i++){
			System.out.println(parameters[i]);
		}
		System.out.println();
	}
}